#include "device_resource_if.h"
#include "hdf_base.h"
#include "hdf_log.h"
#include "osal_mem.h"
#include "can/uart_core.h"
#include "stm32_hal.h"
#include <securec.h>

#ifdef HAL_CAN_MODULE_ENABLED

struct Stm32CanCntlr {
    struct CanCntlr cntlr;
    CAN_HandleTypeDef hcan;
};

CAN_TypeDef *Stm32CanGetInstance(int16_t number)
{
    switch (number) {
        case 1:
            return CAN1;
        default:
            break;
    }
    return NULL;
}

static int32_t Stm32ReadConfigFromHcs(struct Stm32CanCntlr *stm32Can)
{
    const struct DeviceResourceNode *node = NULL;
    struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);

    if (stm32Can == NULL) {
        HDF_LOGE("%s: stm32 cntlr is null", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    node = PlatformDeviceGetDrs(&stm32Can->cntlr.device);
    if (node == NULL) {
        HDF_LOGE("%s: properity node null", __func__);
        return HDF_ERR_INVALID_PARAM;
    }

    if (iface == NULL || iface->GetUint32 == NULL) {
        HDF_LOGE("%s: face is invalid", __func__);
        return HDF_ERR_NOT_SUPPORT;
    }

    if (iface->GetUint32(node, "num", &stm32Can->cntlr.number, 0) != HDF_SUCCESS) {
        HDF_LOGE("%s: read bus number fail", __func__);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

static void Stm32CanEventCb(CAN_HandleTypeDef *hcan)
{
    struct Stm32CanCntlr *stm32Can = NULL;

    if (hcan == NULL) {
        HDF_LOGE("%s: hcan is NULl");
        return;
    }
    stm32Can = CONTAINER_OF(hcan, struct Stm32CanCntlr, hcan);

    //PlatformDeviceNotify(&stm32Can->cntlr.device, CAN_EVENT_MSG_PENDING);
    CanCntlrNotify(&stm32Can->cntlr, CAN_EVENT_MSG_PENDING);
}

static int32_t Stm32CanInit(struct Stm32CanCntlr *stm32Can)
{
    int32_t ret;
    CAN_HandleTypeDef *hcan = NULL;

    HDF_LOGI("%s: enter", __func__);
    if (stm32Can == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }

    ret = Stm32ReadConfigFromHcs(stm32Can);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("Stm32UartInit: read hcs config failed");
        return ret;
    }

    hcan = &stm32Can->hcan;
    /*hcan = (CAN_HandleTypeDef *)OsalMemCalloc(sizeof(*hcan));
    if (hcan == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }*/

    // default value
    hcan->Instance = Stm32CanGetInstance(stm32Can->cntlr.number);
    if (hcan->Instance == NULL) {
        HDF_LOGE("%s: get can:%u inst failed", __func__, stm32Can->cntlr.number);
        return HDF_FAILURE;
    }

    hcan->Instance = CAN1;
    hcan->Init.Prescaler = 16;
    hcan->Init.Mode = CAN_MODE_LOOPBACK;
    hcan->Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan->Init.TimeSeg1 = CAN_BS1_1TQ;
    hcan->Init.TimeSeg2 = CAN_BS2_1TQ;
    hcan->Init.TimeTriggeredMode = DISABLE;
    hcan->Init.AutoBusOff = DISABLE;
    hcan->Init.AutoWakeUp = DISABLE;
    hcan->Init.AutoRetransmission = DISABLE;
    hcan->Init.ReceiveFifoLocked = DISABLE;
    hcan->Init.TransmitFifoPriority = DISABLE;
    if (HAL_CAN_Init(hcan) != HAL_OK)
    {
        HDF_LOGE("%s: hal can init failed", __func__);
        return HDF_FAILURE;
    }

    (void)HAL_CAN_RegisterCallback(hcan, HAL_CAN_RX_FIFO0_MSG_PENDING_CB_ID, Stm32CanEventCb); 
    (void)HAL_CAN_RegisterCallback(hcan, HAL_CAN_RX_FIFO0_FULL_CB_ID, Stm32CanEventCb); 
    (void)HAL_CAN_RegisterCallback(hcan, HAL_CAN_RX_FIFO1_MSG_PENDING_CB_ID, Stm32CanEventCb); 
    (void)HAL_CAN_RegisterCallback(hcan, HAL_CAN_RX_FIFO1_FULL_CB_ID, Stm32CanEventCb); 
    return HDF_SUCCESS;
}

static int32_t Stm32UartDeinit(struct Stm32CanCntlr *stm32Can)
{
    CAN_HandleTypeDef *hcan = NULL;
    HDF_LOGI("%s: enter", __func__);

    if (stm32Can == NULL) {
        return HDF_ERR_INVALID_OBJECT;
    }
    hcan = stm32Can->hcan;
    
    (void)HAL_CAN_DeInit(hcan);
    return HDF_SUCCESS;
}

static int32_t Stm32CanSendMsg(struct CanCntlr *cntlr, struct CanMsg *msg)
{
    uint8_t txData[CAN_DATA_LEN];
    uint32_t txMailbox;
    CAN_TxHeaderTypeDef   txHeader;
    struct Stm32CanCntlr *stm32Can = NULL;

    stm32Can = (struct Stm32CanCntlr *)cntlr->device.priv;
    if (stm32Can == NULL) {
        HDF_LOGE("%s: private data is null", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    if (HAL_CAN_Start(stm32Can->hcan) != HAL_OK) {
        HDF_LOGE("%s: start can bus failed", __func__);
        return HDF_ERR_IO;
    }

    //txHeader.IDE = CAN_ID_STD;
    txHeader.IDE = (msg->ide == 0) ? CAN_ID_STD : CAN_ID_EXT;
    if (msg->ide == 0) {
       txHeader.StdId = msg->id11;
    } else {
       txHeader.ExtId = msg->id29;
    }
    txHeader.RTR = (msg->rtr == 0) ? CAN_RTR_DATA : CAN_RTR_REMOTE;
    txHeader.DLC = msg->dlc;
    txHeader.TransmitGlobalTime = DISABLE;
    if (memcpy_s(txData, CAN_DATA_LEN, msg->data, msg->dlc) != EOK) {
        HDF_LOGE("%s: copy msg failed", __func__);
        return HDF_ERR_IO;
    }

    if(HAL_CAN_AddTxMessage(stm32Can->hcan, &txHeader, txData, &txMailbox) != HAL_OK)
    {
        HDF_LOGE("%s: add tx message failed", __func__);
        return HDF_ERR_IO;
    }

    while(HAL_CAN_GetTxMailboxesFreeLevel(&CanHandle) != 3) {}; // three tx mailbox

    return HDF_SUCCESS;
}

static int32_t Stm32CanReadMsg(struct CanCntlr *cntlr, struct CanMsg *msg)
{
    uint8_t rxData[CAN_DATA_LEN];
    uint32_t txMailbox;
    CAN_RxHeaderTypeDef   rxHeader;
    struct Stm32CanCntlr *stm32Can = NULL;

    stm32Can = (struct Stm32CanCntlr *)cntlr->device.priv;
    if (stm32Can == NULL) {
        HDF_LOGE("%s: private data is null", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    if (HAL_CAN_Start(stm32Can->hcan) != HAL_OK) {
        HDF_LOGE("%s: start can bus failed", __func__);
        return HDF_ERR_IO;
    }

    if(HAL_CAN_GetRxMessage(&CanHandle, CAN_RX_FIFO0, &RxHeader, rxData) != HAL_OK)
    {
        if(HAL_CAN_GetRxMessage(&CanHandle, CAN_RX_FIFO1, &RxHeader, rxData) != HAL_OK) {
            HDF_LOGE("%s: get msg failed", __func__);
            return HDF_ERR_IO;
        }
    }

    msg->ide = (rxData->IDE == CAN_ID_STD) ? 0 : 1;
    if (ide == 0) {
       msg->id11 = txHeader.StdId;
    } else {
       msg->id29 = txHeader.ExtId;
    }
    msg->rtr = (rxData.RTR == CAN_RTR_DATA) ? 0 : 1;
    if (memcpy_s(msg->data, CAN_DATA_LEN, rxData, rxData.DLC) != EOK) {
        HDF_LOGE("%s: copy msg failed", __func__);
        return HDF_ERR_IO;
    }
    msg->dlc = rxData.DLC;

    return HDF_SUCCESS;
}

#define STM32_FILTER_BANK_NUM 14
#define STM32_SLAVE_START_FILTER_BANK 14

static struct CanFilter *g_filterMap[STM32_FILTER_BANK_NUM] = { 0 };

static int32_t Stm32CanNoFilterConfig(struct Stm32CanCntlr *stm32Can)
{
    CAN_FilterTypeDef  sFilterConfig;

    sFilterConfig.FilterBank = 0;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    sFilterConfig.SlaveStartFilterBank = 14;
    if(HAL_CAN_ConfigFilter(stm32Can->hcan, &sFilterConfig) != HAL_OK)
    {
        HDF_LOGE("%s: config filter banck 0 failed", __func__);
        return HDF_ERR_IO;
    }
    return HDF_SUCCESS;
}

static int32_t Stm32CanAddFilter(struct CanCntlr *cntlr, struct CanFilter *filter)
{
    int32_t bank;
    uint32_t af;
    uint32_t afMask;
    CAN_FilterTypeDef sFilterConfig;

    for (bank = 0; bank < STM32_FILTER_BANK_NUM; bank++) {
        if (g_filterMap[bank] == NULL) {
            break;
        }
    }

    if (bank >= STM32_FILTER_BANK_NUM) {
        HDF_LOGE("%s: no free filter bank", __func__);
        return HDF_FAILURE;
    }

    g_filterMap[bank] = filter;


    sFilterConfig.FilterBank = bank;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;

    af = (filter.id << 3),(filter.ide << 2),(filter.rtr << 1);
    afMask = (filter.idMask << 3),(filter.ideMask << 2),(filter.rtrMask << 1);
    sFilterConfig.FilterIdHigh = af >> 16;
    sFilterConfig.FilterIdLow = af & 0xFFFF;
    sFilterConfig.FilterMaskIdHigh = afMask >> 16;
    sFilterConfig.FilterMaskIdLow = afMask & 0xFFFF;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    sFilterConfig.SlaveStartFilterBank = STM32_SLAVE_START_FILTER_BANK;
    if(HAL_CAN_ConfigFilter(stm32Can->hcan, &sFilterConfig) != HAL_OK)
    {
        HDF_LOGE("%s: config filter bank:%d failed", __func__, bank);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

static int32_t Stm32CanDelFilter(struct CanCntlr *cntlr, struct CanFilter *filter)
{
    int32_t bank;
    CAN_FilterTypeDef sFilterConfig;

    for (bank = 0; bank < STM32_FILTER_BANK_NUM; bank++) {
        if (g_filterMap[bank] == filter) {
            break;
        }
    }
    if (bank >= STM32_FILTER_BANK_NUM) {
        HDF_LOGE("%s: filter not found", __func__);
        return HDF_FAILURE;
    }

    sFilterConfig.FilterActivation = DISABLE;
    if(HAL_CAN_ConfigFilter(stm32Can->hcan, &sFilterConfig) != HAL_OK)
    {
        HDF_LOGE("%s: config filter bank:%d failed", __func__, bank);
        return HDF_FAILURE;
    }

    g_filterMap[bank] == NULL;
    return HDF_SUCCESS;
}

enum STM32_CAN_SPEED
{
    CAN_SPEED_1M   = 1000UL * 1000,/* 1 MBit/sec   */
    CAN_SPEED_800K = 1000UL * 800, /* 800 kBit/sec */
    CAN_SPEED_500K = 1000UL * 500, /* 500 kBit/sec */
    CAN_SPEED_250K = 1000UL * 250, /* 250 kBit/sec */
    CAN_SPEED_125K = 1000UL * 125, /* 125 kBit/sec */
    CAN_SPEED_100K = 1000UL * 100, /* 100 kBit/sec */
    CAN_SPEED_50K  = 1000UL * 50,  /* 50 kBit/sec  */
    CAN_SPEED_20K  = 1000UL * 20,  /* 20 kBit/sec  */
    CAN_SPEED_10K  = 1000UL * 10   /* 10 kBit/sec  */
};

struct Stm32SpeedConfigMap  {
    uint32_t speed,
    uint32_t sjw,
    uint32_t tsg1,
    uint32_t tsg2,
    uint32_t prescaler;
};

static const struct Stm32SpeedConfigMap g_speedMaps[] = {
    {CAN_SPEED_1M, CAN_SJW_2TQ, CAN_BS1_5TQ, CAN_BS2_2TQ, 10},
    {CAN_SPEED_800K, CAN_SJW_2TQ, CAN_BS1_14TQ, CAN_BS2_5TQ, 5},
    {CAN_SPEED_500K, CAN_SJW_2TQ, CAN_BS1_7TQ, CAN_BS2_2TQ, 16},
    {CAN_SPEED_250K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 20},
    {CAN_SPEED_125K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 40},
    {CAN_SPEED_100K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 50},
    {CAN_SPEED_50K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 100},
    {CAN_SPEED_20K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 250},
    {CAN_SPEED_10K, CAN_SJW_2TQ, CAN_BS1_13TQ, CAN_BS2_2TQ, 500}
};

static int32_t Stm32CanSetSpeed(struct Stm32CanCntlr *stm32Can, uint32_t speed)
{
    int32_t i;
    struct Stm32SpeedConfigMap *cfg;

    for (i = 0; i < sizeof(g_speedMaps) / sizeof(g_speedMaps[0]); i++) {
        if (g_speedMaps[i].speed == speed) {
            break;
        }
    }

    if (i >= (sizeof(g_speedMaps) / sizeof(g_speedMaps[0]))) {
        HDF_LOGE("%s: speed: %u not support", __func__, speed);
        return HDF_ERR_NOT_SUPPORT;
    }

    cfg = &g_speedMaps[i];
    stm32Can->hcan.Init.SyncJumpWidth = cfg->sjw;
    stm32Can->hcan.Init.TimeSeg1 = cfg->tsg1;
    stm32Can->hcan.Init.TimeSeg2 = cfg->tsg2;
    stm32Can->hcan.Init.Prescaler = cfg->prescaler;
    /* init can */
    /*if (HAL_CAN_Init(&stm32Can->hcan) != HAL_OK)
    {
        HDF_LOGE("%s: hal can init failed", __func__);
        return HDF_FAILURE;
    };*/

    return HDF_SUCCESS;
}

static int32_t Stm32CanGetSpeed(struct Stm32CanCntlr *stm32Can, uint32_t *speed)
{
    struct Stm32SpeedConfigMap *cfg;
    CAN_InitTypeDef *init =  &stm32Can->hcan.Init;

    for (i = 0; i < sizeof(g_speedMaps) / sizeof(g_speedMaps[0]); i++) {
        cfg = &g_speedMaps[i];
        if (cfg->sjw == init->SyncJumpWidth && cfg->prescaler == init->Prescaler &&
            cfg->tsg1 == init->TimeSeg1 && cfg->tsg2 == init->TimeSeg2) {
            *speed = cfg->speed;
            return HDF_SUCCESS;
        }
    }
    HDF_LOGE("%s: cur speed cfgs not found in table", __func__);
    return HDF_FAILURE;
}

static int32_t Stm32CanSetMode(struct Stm32CanCntlr *stm32Can, int32_t mode)
{
    switch (mode)
    {
        case CAN_BUS_NORMAL:
            stm32Can->hcan.Init.Mode = CAN_MODE_NORMAL;
            break;
        case CAN_BUS_LOOPBACK:
            stm32Can->hcan.Init.Mode = CAN_MODE_LOOPBACK;
            break;
        default:
            return HDF_ERR_NOT_SUPPORT;
    }
    return HDF_SUCCESS;
}

static int32_t Stm32CanSetMode(struct Stm32CanCntlr *stm32Can, int32_t *mode)
{
    switch (stm32Can->hcan.Init.Mode)
    {
        case CAN_MODE_NORMAL:
            *mode = CAN_BUS_NORMAL;
            break;
        case CAN_MODE_LOOPBACK:
            *mode = CAN_BUS_LOOPBACK;
            break;
        default:
            return HDF_ERR_NOT_SUPPORT;
    }
    return HDF_SUCCESS;
}

static int32_t Stm32CanSetCfg(struct Stm32CanCntlr *stm32Can, struct CanConfig *cfg)
{
    int32_t ret;

    if ((ret = Stm32CanSetSpeed(stm32Can, cfg->speed) != HDF_SUCCESS)) {
        HDF_LOGE("%s: set speed failed", __func__);
        return ret;
    }

    if ((ret = Stm32CanSetMode(stm32Can, cfg->mode) != HDF_SUCCESS)) {
        HDF_LOGE("%s: set mode failed", __func__);
        return ret;
    }

    if (HAL_CAN_Init(hcan) != HAL_OK)
    {
        HDF_LOGE("%s: hal can init failed", __func__);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t Stm32CanGetCfg(struct Stm32CanCntlr *stm32Can, struct CanConfig *cfg)
{
    int32_t ret;

    if ((ret = Stm32CanGetSpeed(stm32Can, &cfg->speed) != HDF_SUCCESS)) {

        HDF_LOGE("%s: get speed failed", __func__);
        return ret;
    }

    if ((ret = Stm32CanGetMode(stm32Can, &cfg->mode) != HDF_SUCCESS)) {
        HDF_LOGE("%s: get mode failed", __func__);
        return ret;
    }

    return HDF_SUCCESS;
}

struct CanCntlrMethod g_stm32CanMethod = {
    .sendMsg = Stm32CanSendMsg,
    .readMsg = Stm32CanReadMsg,
    .addFilter = Stm32CanAddFilter,
    .delFilter = Stm32CanDelFilter,
    .setCfg = Stm32CanGetCfg,
    .getCfg = Stm32CanSetCfg,
};

static int32_t HdfStm32CanBind(struct HdfDeviceObject *device)
{
    struct Stm32CanCntlr *stm32Can = NULL;

    stm32Can = (struct Stm32CanCntlr *)OsalMemCalloc(sizeof(*stm32Can));
    if (stm32Can == NULL) {
        return HDF_ERR_MALLOC_FAIL;
    }

    PlatformDeviceBind(&stm32Can->cntlr.device, device);
    HDF_LOGI("%s: bind success!", __func__);
    return HDF_SUCCESS;
}

int32_t HdfStm32CanInit(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct PlatformDevice *pdevice = NULL;
    struct Stm32CanCntlr *stm32Can = NULL;

    HDF_LOGI("%s: entry", __func__);
    if (device == NULL) {
        HDF_LOGE("%s: device is null", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    pdevice = PlatformDeviceFromHdf(device);
    if (pdevice == NULL) {
        HDF_LOGE("%s: platform device not bind", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    stm32Can = (struct Stm32CanCntlr *)pdevice;
    ret = Stm32CanInit(stm32Can);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: can init error: %d", __func__, ret);
        return ret;
    }

    ret = Stm32CanNoFilterConfig(stm32Can);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: can no filter config failed: %d", __func__, ret);
        return ret;
    }

    stm32Can->cntlr.method = &g_stm32CanMethod;
    stm32Can->cntlr.device.priv = stm32Can;

    ret = CanCntlrAdd(&stm32Can->cntlr);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: add cntlr failed: %d", __func__, ret);
        return ret;
    }
    HDF_LOGI("%s: can-%u init success!", __func__, stm32Can->cntlr.number);
    return HDF_SUCCESS;
}

void HdfStm32CanRelease(struct HdfDeviceObject *device)
{
    struct Stm32CanCntlr *stm32Can = NULL;

    HDF_LOGI("%s: entry", __func__);
    if (device == NULL) {
        HDF_LOGE("%s: device is null", __func__);
        return;
    }

    stm32Can = (struct Stm32CanCntlr *)PlatformDeviceExtract(device);
    if (stm32Can == NULL) {
        HDF_LOGE("%s: platform device not bind", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }

    (void)Stm32CanDeinit(stm32Can);
    OsalMemFree(stm32Can);

    (void)CanCntlrDel(&stm32Can->cntlr);
}

struct HdfDriverEntry g_hdfCanDriver = {
    .moduleVersion = 1,
    .moduleName = "stm32_can_driver",
    .Bind = HdfStm32CanBind,
    .Init = HdfStm32CanInit,
    .Release = HdfStm32CanRelease,
};

HDF_INIT(g_hdfCanDriver);
#endif /* HAL_UART_MODULE_ENABLED */
